package com.campus.merchant.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campus.common.bean.common.PageUtil;
import com.campus.common.bean.common.Resp;
import com.campus.common.enums.*;
import com.campus.common.exception.BusinessException;
import com.campus.common.util.ProfitCalculator;
import com.campus.merchant.bean.order.OrderListQueryParam;
import com.campus.merchant.dto.RefundRequestDTO;
import com.campus.merchant.dto.RefundResponseDTO;
import com.campus.merchant.entity.*;
import com.campus.merchant.feign.RefundFeignClient;
import com.campus.merchant.mapper.*;
import com.campus.merchant.vo.order.OrderDetailVO;
import com.campus.merchant.vo.order.OrderVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author ZhaoYuJie
 * @since 2025-04-18
 */
@Service
@Slf4j
public class OrderService extends ServiceImpl<OrderMapper, Order> {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderGoodsMapper orderGoodsMapper;

    @Value("${campus.profit.delivery-commission-rate:0.2}")
    private BigDecimal deliveryCommissionRate;
    
    @Value("${campus.profit.service-fee-rate:0.1}")
    private BigDecimal serviceFeeRate;
    @Autowired
    private PaymentMethodMapper paymentMethodMapper;
    @Autowired
    private UserCouponMapper userCouponMapper;
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private OrderCancelMessageProducer orderCancelMessageProducer;
    @Autowired
    private MealReadyMessageProducer mealReadyMessageProducer;
    @Autowired
    private OrderCompleteMessageProducer orderCompleteMessageProducer;
    @Autowired
    private RefundRecordService refundRecordService;
    @Autowired
    private RefundFeignClient refundFeignClient;
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private SessionService sessionService;
    @Autowired
    private UserCouponService userCouponService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PointsRecordMapper pointsRecordMapper;



    private List<OrderVO> convertToOrderVOList(List<Order> orders) {
        List<OrderVO> voList = new ArrayList<>();
        for (Order order : orders) {
            OrderVO vo = new OrderVO();
            BeanUtil.copyProperties(order, vo);
            // 查询订单商品
            List<OrderGoods> goodsList = orderGoodsMapper.selectList(
                new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderId, order.getId())
            );
            List<OrderVO.OrderGoodsVO> goodsVOList = new ArrayList<>();
            for (OrderGoods goods : goodsList) {
                OrderVO.OrderGoodsVO goodsVO = new OrderVO.OrderGoodsVO();
                BeanUtil.copyProperties(goods, goodsVO);
                goodsVOList.add(goodsVO);
            }
            vo.setGoods(goodsVOList);
            voList.add(vo);
        }
        return voList;
    }
    
    public PageInfo<OrderVO> getOrderListPage(OrderListQueryParam param) {
        // 使用正确的分页参数获取订单列表
        PageInfo<Order> pageInfo = PageHelper.startPage(param.getPageNo(), param.getPageSize())
                .doSelectPageInfo(() -> getOrderPage(param));
        List<OrderVO> orderVOList = convertToOrderVOList(pageInfo.getList());

        return PageUtil.convertPageInfo(pageInfo, orderVOList);
    }

    private List<Order> getOrderPage(OrderListQueryParam param) {
        LambdaQueryWrapper<Order>  wrapper = Wrappers.<Order>lambdaQuery()
                .eq(param.getMerchantId() != null, Order::getMerchantId, param.getMerchantId())
                .eq(param.getStatus() != null, Order::getStatus, param.getStatus());

        if(param.getStatus() == null || param.getStatus() == OrderStatusEnum.COMPLETED.getValue()){
            wrapper.orderByDesc(Order::getCreateTime);
        }else{
            wrapper.orderByAsc(Order::getCreateTime);
        }

        List<Order> orders = baseMapper.selectList(wrapper);

        return orders;
    }

    /**
     * 获取商户待处理订单数量
     * @param merchantId 商户ID
     * @return 待处理订单数量
     */
    public Long getPendingOrderCount(Long merchantId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getMerchantId, merchantId)
               .eq(Order::getStatus, OrderStatusEnum.PENDING_ACCEPTANCE.getValue());
        return orderMapper.selectCount(wrapper);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public boolean acceptOrder(String orderId) {
        Order order = getById(orderId);
        if (order == null) {
            return false;
        }
        //只有待接单状态的订单才能接单
        if (order.getStatus() != OrderStatusEnum.PENDING_ACCEPTANCE.getValue()) {
            throw new BusinessException("当前订单不是待接单状态");
        }
        order.setStatus(OrderStatusEnum.PROCESSING.getValue());
        order.setStatusText(OrderStatusEnum.PROCESSING.getText());
        order.setMerchantProcess(MerchantProcessEnum.PREPARING_MEAL.getValue());
        order.setMerchantProcessText(MerchantProcessEnum.PREPARING_MEAL.getText());
        if(order.getDeliveryType() == DeliveryTypeEnum.TAKEOUT.getValue()){
            order.setDeliveryProcess(DeliveryProcessEnum.PENDING_GRAB.getValue());
            order.setDeliveryProcessText(DeliveryProcessEnum.PENDING_GRAB.getText());
        }

        return updateById(order);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public boolean rejectOrder(String orderId, String cancelReason) {
        // 默认操作人类型为商户
        return rejectOrder(orderId, cancelReason, 1);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public boolean rejectOrder(String orderId, String cancelReason, Integer operatorType) {
        Order order = getById(orderId);
        if (order == null) {
            return false;
        }
        // 只有待接单的订单才能被拒单
        if (order.getStatus() != OrderStatusEnum.PENDING_ACCEPTANCE.getValue()) {
            throw new BusinessException("当前订单不是待接单状态");
        }
        // 检查订单是否已支付，如果已支付则需要退款
        boolean needRefund = OrderStatusEnum.PENDING_ACCEPTANCE.getValue()==order.getStatus()
                && order.getTransactionId() != null;
        
        // 先执行本地事务操作：更新订单状态
        order.setStatus(OrderStatusEnum.CANCELLED.getValue());
        order.setStatusText(OrderStatusEnum.CANCELLED.getText());
        order.setCancelTime(LocalDateTime.now());
        order.setCancelReason(cancelReason);
        
        boolean result = updateById(order);

        // 如果使用了优惠券，需要退还优惠券
        if (order.getUserCouponId() != null) {
            userCouponService.update(Wrappers.<UserCoupon>lambdaUpdate()
                    .eq(UserCoupon::getId, order.getUserCouponId())
                    .set(UserCoupon::getStatus, UserCouponStatusEnum.AVAILABLE.getValue())
                    .set(UserCoupon::getOrderId, null)
                    .set(UserCoupon::getUseTime, null));
        }

        // 如果使用了积分，需要退还积分
        if (order.getPointsUsed() != null && order.getPointsUsed() > 0) {
            // 退还用户积分
            userMapper.addPoints(order.getUserId(), order.getPointsUsed());

            // 记录积分退还记录
            PointsRecord pointsRecord = new PointsRecord();
            pointsRecord.setUserId(order.getUserId());
            pointsRecord.setPoints(order.getPointsUsed());
            pointsRecord.setType(PointsRecordTypeEnum.RETURN.getValue());
            pointsRecord.setSource(PointsRecordSourceEnum.ORDER.getValue());
            pointsRecord.setSourceId(order.getId());
            pointsRecord.setDescription("商户拒单退还积分");
            pointsRecordMapper.insert(pointsRecord);

            // 积分变动影响了用户信息，要更新用户信息到Redis
            userService.updateUserInfoToRedis(order.getUserId());
        }
        
        // 如果订单已支付，申请退款（本地事务操作完成后执行）
        if (result && needRefund) {
            Integer operatorId = null;
            // 根据操作人类型获取操作人ID
            if (operatorType == 1) { // 商户操作
                operatorId = sessionService.getUserInfo().getId();
            } else if (operatorType == 3) { // 系统操作
                operatorId = 0; // 系统操作使用0作为操作人ID
            }
            // 获取商户信息
            Merchant merchant = merchantMapper.selectById(order.getMerchantId());
            if (merchant == null || merchant.getSubMchid() == null) {
                throw new BusinessException("商户信息不存在或子商户号未配置");
            }

            // 构建退款请求DTO
            RefundRequestDTO refundRequestDTO = new RefundRequestDTO();
            refundRequestDTO.setSubMchid(merchant.getSubMchid());
            refundRequestDTO.setOrderId(order.getId());
            refundRequestDTO.setRefundAmount(order.getActualPay());
            refundRequestDTO.setRefundReason(cancelReason);
            refundRequestDTO.setRefundType(operatorType); // 退款类型：1-商户拒单，2-用户取消，3-系统退款，4-客服退款
            refundRequestDTO.setOperatorId(operatorId);
            refundRequestDTO.setOperatorType(operatorType);
            refundRequestDTO.setWechatTransactionId(order.getTransactionId());
            
            // 调用支付服务的退款接口，退款失败将抛出异常并回滚事务
            Resp<RefundResponseDTO> refundResult = refundFeignClient.applyRefund(refundRequestDTO);
            if ("0".equals(refundResult.getCode())) {
                log.info("拒单退款申请成功，订单号: {}, 操作人类型: {}, 退款单号: {}", 
                    orderId, operatorType, refundResult.getData().getRefundNo());
            } else {
                log.error("拒单退款申请失败，订单号: {}, 操作人类型: {}, 错误信息: {}", 
                    orderId, operatorType, refundResult.getMessage());
                throw new BusinessException("退款申请失败：" + refundResult.getMessage());
            }
        }
        
        // 发送订单取消通知给顾客
        if (result) {
            try {
                // 获取用户信息
                User user = userService.getById(order.getUserId());
                if (user != null && user.getOpenid() != null) {
                    // 通过Kafka发送订单取消消息到顾客端
                    orderCancelMessageProducer.sendOrderCancelMessage(
                        user.getOpenid(),
                        order.getId(),
                        order.getActualPay(),
                        cancelReason
                    );
                }
            } catch (Exception e) {
                // 订单取消成功，但通知发送失败不影响业务流程
                log.error("发送订单取消通知失败，订单号: {}", orderId, e);
            }
        }
        
        return result;
    }
    
    @Transactional(rollbackFor = Exception.class)
    public boolean finishMeal(String orderId) {
        Order order = getById(orderId);
        if (order == null) {
            return false;
        }
        // 只有备餐中状态的订单才能出餐
        if (!MerchantProcessEnum.PREPARING_MEAL.getValue().equals(order.getMerchantProcess())) {
            return false;
        }
        order.setMerchantProcess(MerchantProcessEnum.MEAL_READY.getValue());
        order.setMerchantProcessText(MerchantProcessEnum.MEAL_READY.getText());
        
        // 如果是外卖订单，发送出餐消息给配送端
        if (order.getDeliveryType() == DeliveryTypeEnum.TAKEOUT.getValue()) {
            try {
                mealReadyMessageProducer.sendMealReadyMessage(order.getId(), order.getDeliveryId());
                log.info("外卖订单{}出餐消息已发送", orderId);
            } catch (Exception e) {
                log.error("发送外卖订单{}出餐消息失败", orderId, e);
            }
        }
        
        //根据deliveryType判断，如果是堂食或自取，则订单状态设置为已完成.
        if (order.getDeliveryType() == DeliveryTypeEnum.DINING_IN.getValue()
                || order.getDeliveryType() == DeliveryTypeEnum.SELF_PICKUP.getValue()) {
            order.setStatus(OrderStatusEnum.COMPLETED.getValue());
            order.setStatusText(OrderStatusEnum.COMPLETED.getText());
            order.setFinishTime(LocalDateTime.now());
            
            // 计算各方收益
            calculateAndSetProfit(order);
            
            // 发送订单完成通知给顾客
            try {
                // 获取用户信息
                User user = userService.getById(order.getUserId());
                if (user != null && user.getOpenid() != null) {
                    // 获取订单商品信息用于构建货品名称
                    List<OrderGoods> goodsList = orderGoodsMapper.selectList(
                        new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderId, order.getId())
                    );
                    String goodsName = "";
                    if (!goodsList.isEmpty()) {
                        if (goodsList.size() == 1) {
                            goodsName = goodsList.get(0).getName();
                        } else {
                            goodsName = goodsList.get(0).getName() + "等" + goodsList.size() + "件商品";
                        }
                    }
                    
                    // 通过Kafka发送订单完成消息到顾客端
                    orderCompleteMessageProducer.sendOrderCompleteMessage(
                        user.getOpenid(),
                        order.getId(),
                        goodsName,
                        order.getActualPay(),
                        LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                        "商家已出餐，请及时取餐。"
                    );
                    log.info("订单完成通知已发送，订单号: {}", orderId);
                }
            } catch (Exception e) {
                // 订单完成成功，但通知发送失败不影响业务流程
                log.error("发送订单完成通知失败，订单号: {}", orderId, e);
            }
        }
        return updateById(order);
    }

    public OrderDetailVO getOrderDetail(String orderId) {
        Order order = getById(orderId);
        if (order != null) {
            OrderDetailVO orderDetailVO = new OrderDetailVO();
            BeanUtil.copyProperties(order, orderDetailVO);
            // 查询订单商品
            List<OrderGoods> goodsList = orderGoodsMapper.selectList(
                new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderId, order.getId())
            );
            List<OrderVO.OrderGoodsVO> goodsVOList = new ArrayList<>();
            for (OrderGoods goods : goodsList){
                OrderVO.OrderGoodsVO goodsVO = new OrderVO.OrderGoodsVO();
                BeanUtil.copyProperties(goods, goodsVO);
                goodsVOList.add(goodsVO);
            }
            orderDetailVO.setGoods(goodsVOList);

            PaymentMethod paymentMethod = paymentMethodMapper.selectById(order.getPaymentMethodId());
            orderDetailVO.setPaymentMethod(paymentMethod);

            if(order.getUserCouponId() != null && order.getUserCouponId() != 0){
                UserCoupon userCoupon = userCouponMapper.selectById(order.getUserCouponId());
                Coupon coupon = couponMapper.selectById(userCoupon.getCouponId());
                orderDetailVO.setCoupon(coupon);
            }

            return orderDetailVO;
        }
        return null;
    }
    
    /**
     * 计算并设置订单各方收益
     * @param order 订单对象
     */
    private void calculateAndSetProfit(Order order) {
        try {
            // 获取订单金额信息
            BigDecimal actualPay = order.getActualPay();
            BigDecimal deliveryFee = order.getDeliveryFee() != null ? order.getDeliveryFee() : BigDecimal.ZERO;
            
            // 计算各方收益
            ProfitCalculator.ProfitResult profitResult = ProfitCalculator.calculateProfit(
                actualPay, deliveryFee, deliveryCommissionRate, serviceFeeRate);
            
            // 设置收益字段
            order.setDeliveryProfit(profitResult.getDeliveryProfit());
            order.setPlatformProfit(profitResult.getPlatformProfit());
            order.setMerchantProfit(profitResult.getMerchantProfit());
            
            log.info("订单{}收益计算完成 - 配送员收益:{}, 平台收益:{}, 商户收益:{}", 
                order.getId(), 
                profitResult.getDeliveryProfit(), 
                profitResult.getPlatformProfit(), 
                profitResult.getMerchantProfit());
                
        } catch (Exception e) {
            log.error("订单{}收益计算失败", order.getId(), e);
            // 收益计算失败不影响订单完成流程
        }
    }
}